﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Gnosis.Babel;
using Gnosis.SQLite.Clauses;

namespace Gnosis.SQLite.Statements
{
    public class SelectStatement<T>
        : Statement, ISelect<T>
        where T : ISource, new()
    {

        public SelectStatement()
            : base()
        {
            _from = new From(new T());
        }

        private SelectType _selectType = SelectType.All;
        private readonly IList<IExpression> _results = new List<IExpression>();
        private From _from;
        private Where _where;
        private readonly IList<IColumnName> _groupByColumns = new List<IColumnName>();
        private GroupBy _groupBy;
        private Having _having;
        private readonly IList<IOrderingTerm> _orderByTerms = new List<IOrderingTerm>();
        private OrderBy _orderBy;

        protected override IList<IExpression> GetChildren()
        {
            IList<IExpression> children = new List<IExpression>();
            children.Add(_selectType);

            if (_results.Count > 0)
                children.Add(new CommaList(_results));

            if (_from != null)
                children.Add(_from);

            if (_where != null)
                children.Add(_where);

            if (_groupBy != null)
                children.Add(_groupBy);

            if (_having != null)
                children.Add(_having);

            if (_orderBy != null)
                children.Add(_orderBy);

            return children;
        }

        #region ISelect<T> Members

        public ISelect<T> All
        {
            get
            { 
                _selectType = SelectType.All;
                return this;
            }
        }

        public ISelect<T> Distinct
        {
            get
            {
                _selectType = SelectType.Distinct;
                return this;
            }
        }

        public ISelect<T> Column(Func<T, IValue> value)
        {
            _results.Add(value.Invoke(new T()));
            return this;
        }

        public ISelect<T> Column(Func<T, IValue> value, string alias)
        {
            _results.Add(new ColumnAlias(value.Invoke(new T()), new TextLiteral(alias)));
            return this;
        }

        public ISelect<T> Where(IPredicate predicate)
        {
            _where = (predicate != null) ? new Where(predicate) : null;
            return this;
        }

        public ISelect<T> GroupBy(Func<T, IColumnName> column)
        {
            _groupByColumns.Add(column);
            return this;
        }

        public ISelect<T> Having(IPredicate predicate)
        {
            _having = (predicate != null) ? new Having(predicate) : null;
            return this;
        }

        public ISelect<T> OrderBy(params IOrderingTerm[] columns)
        {
            return OrderBy((IEnumerable<IOrderingTerm>)columns);
        }

        public ISelect<T> OrderBy(IEnumerable<IOrderingTerm> columns)
        {
            _orderBy = (columns != null) ? new OrderBy(columns.ToList<IOrderingTerm>()) : null;
            return this;
        }

        #endregion

        #region ISource Members

        public IInteger LastInsertedId
        {
            get
            {
                return new LastInsertRowId();
            }
        }

        #endregion
    }
}
